/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package managedbean;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.event.PhaseEvent;

// Entities
import entity.TouristAccountEntity;
import util.entityhelper.GrouponHelper;
import entity.PurchasedGrouponEntity;
// EJB
import session.stateful.TouristSessionBean;

import session.stateful.GrouponSessionBean;
// Payment
import com.paypal.sdk.core.nvp.NVPDecoder;
import com.paypal.sdk.core.nvp.NVPEncoder;
import com.paypal.sdk.profiles.APIProfile;
import com.paypal.sdk.profiles.ProfileFactory;
import com.paypal.sdk.services.NVPCallerServices;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import session.stateless.PaymentProcessingSessionBeanRemote;

/**
 *
 * @author NGUYEN CONG DAT
 */
@ManagedBean(name = "purchaseGrouponManagerBean")
@SessionScoped
public class PurchaseGrouponManagerBean {

    // Note for Thai Duy
    /* Nhung thu lam duoc
     * Nhung thu lien quan den groupon (ko phai la groupon Application) trong managedbean phai dung den GrouponHelper, purpose la de retrieve
     * quantityBought !!!
     * Nhung thu can lam
     * 1. Vao TimerSessionBean viet tiep phan refund cho anh, loi paypalTransactionId va CorrelationId de tra tien lai cho khach hang
     * 2. Ngay sau khi refund, email bao tourist ve viec huy groupon purchase. 
     * 3. Hoac la sau khi close 1 groupon deal, neu so nguoi >= minimum, generate groupon code dua tren ha`m secureRandom, email bao cho khach hang
     * cai issuedGroupon minh moi generate
     * 4. Chinh cai may cai page 
     * 
     * Chuc nang can implement nua
     * 1. Stakeholders va tourists verify 1 groupon
     * 2. Stakeholders xem nhung tourist nao da mua groupon
     * 3. Stakeholders record 1 groupon da du`ng (giong nhu show/no show) - chi duoc declare 1 lan duy nhat
     */
    @EJB
    private GrouponSessionBean grouponSessionBean;
    @EJB
    private TouristSessionBean touristSessionBean;
    @EJB
    private PaymentProcessingSessionBeanRemote ppsbr;
    private PurchasedGrouponEntity purchase;
    private GrouponHelper selectedGroupon;
    private TouristAccountEntity tourist;
    private List<GrouponHelper> currentlyOfferedGrouponList;
    private List<String> expiryYearList;
    //Other supporting variables
    private Integer percentDiscount = 0;
    private Double savingAmount = 0.0;
    private Double totalAmount = 0.0;
    private boolean reloadOrderPage = false;
    private boolean showLoginPanel = false;
    private String username = "";
    private String password = "";
    private String hostIp;
    private String nameOnCard = "";
    private String creditCardType = "";
    private String CCV2 = "";
    private String expiryMonth = "";
    private String expiryYear = "";
    private String creditCardNumberGroup1 = "";
    private String creditCardNumberGroup2 = "";
    private String creditCardNumberGroup3 = "";
    private String creditCardNumberGroup4 = "";
    //
    private String transactionId = "";
    private String correlationId = "";
    private String paymentDate = "";
    private FacesContext ctx = FacesContext.getCurrentInstance();

    /** Creates a new instance of PurchaseGrouponManagerBean */
    public void loginVistor(ActionEvent event) throws IOException {
        System.out.println("PurchaseGrouponManagerBean:loginVisitor()");
        try {
            setTourist(touristSessionBean.getTouristByUsername(getUsername()));
            if (tourist == null) {
                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(
                        FacesMessage.SEVERITY_ERROR, "Username or password is incorrect", ""));
            } else {
                if (!password.equals(tourist.getPassword())) {
                    FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(
                            FacesMessage.SEVERITY_ERROR, "Username or password is incorrect", ""));
                } else {
                    String serverName = ctx.getExternalContext().getRequestServerName();
                    int serverPort = (Integer) ctx.getExternalContext().getSessionMap().get("serverPort");
                    String contextPath = ctx.getExternalContext().getRequestContextPath();
                    ctx.getExternalContext().redirect("http://" + serverName + ":" + serverPort + contextPath + "tourist/VisitorConfirmGrouponOrder.xhtml");
                }
            }
        } catch (Exception e) {
            System.out.println("Exception !!!!");
        }
    }

    public PurchaseGrouponManagerBean() {
        currentlyOfferedGrouponList = new ArrayList<GrouponHelper>();
        purchase = new PurchasedGrouponEntity();
        selectedGroupon = new GrouponHelper(null, null);
        tourist = (TouristAccountEntity) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("tourist");
        expiryYearList = new ArrayList<String>();
        Date date = new Date();
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        int year = calendar.get(Calendar.YEAR);
        for (int i = 0; i <= 15; i++) {
            expiryYearList.add(Integer.toString(year + i));
        }
    }

    // After tourist clicks on "Submit Order"
    public void submitOrderAndPaymentInformation(ActionEvent event) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
            String creditCardNumber = getCreditCardNumberGroup1() + getCreditCardNumberGroup2()
                    + getCreditCardNumberGroup3() + getCreditCardNumberGroup4();
            String firstName = tourist.getTourist().getFirstName();
            String lastName = tourist.getTourist().getLastName();
            String email = tourist.getTourist().getEmail();
            String salesAmt = String.valueOf(totalAmount);
            String expDate = "" + getExpiryMonth() + getExpiryYear();
            String paypalTransactionId = null;
            String paypalCorrelationId = null;
            org.apache.log4j.BasicConfigurator.configure();

            NVPDecoder paypalResponse = DoDirectPaymentCode("Sale", salesAmt, creditCardType, creditCardNumber,
                    expDate, CCV2, email, firstName, lastName);

            // ack variable
            boolean success = false;
            String response = "";
            String statusMessage = "";

            for (Object objKey : paypalResponse.getMap().keySet()) {
                System.out.println(objKey.toString() + " = " + paypalResponse.getMap().get(objKey));

                if (objKey.toString().equals("L_LONGMESSAGE0")) {
                    statusMessage = (String) paypalResponse.getMap().get(objKey);

                    FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO,
                            "Payment Result: " + statusMessage, ""));
                }

                // Ack is a success
                if (objKey.toString().equals("ACK")) {
                    response = (String) paypalResponse.getMap().get(objKey);
                    if (response.equals("Success")) {
                        success = true;
                    }
                }
                if (objKey.toString().equals("TRANSACTIONID")) {
                    paypalTransactionId = (String) paypalResponse.getMap().get(objKey);
                }
                if (objKey.toString().equals("CORRELATIONID")) {
                    paypalCorrelationId = (String) paypalResponse.getMap().get(objKey);
                }
            }

            // transaction successful
            if (success == true) {
                System.out.println("Success");
                Date today = new Date();
                paymentDate = sdf.format(today);
                transactionId = paypalTransactionId;
                correlationId = paypalCorrelationId;
                // go to success page, print receipt
                String serverName = ctx.getExternalContext().getRequestServerName();
                int serverPort = (Integer) ctx.getExternalContext().getSessionMap().get("serverPort");
                String contextPath = ctx.getExternalContext().getRequestContextPath();
                ctx.getExternalContext().redirect("http://" + serverName + ":" + serverPort + contextPath + "/tourist/VisitorFinishGrouponPayment.xhtml");
                grouponSessionBean.addGrouponPurchase(selectedGroupon.getGroupon().getId(), tourist.getId(), purchase, paypalTransactionId, paypalCorrelationId);
                purchase = new PurchasedGrouponEntity();
            } else {
                System.out.println("Payment failed");
                // Print out payment error
                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR,
                        "Payment Error: " + statusMessage, ""));
            }
        } catch (Exception e) {
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR,
                    "Payment Error: ", "Please try again later"));
        }
    }

    // Paypal !!!
    public NVPDecoder DoDirectPaymentCode(String paymentAction, String amount, String cardType,
            String acct, String expdate, String cvv2, String email,
            String firstName, String lastName) {
        NVPEncoder encoder = new NVPEncoder();
        NVPDecoder decoder = new NVPDecoder();

        try {

            NVPCallerServices caller = new NVPCallerServices();
            APIProfile profile = ProfileFactory.createSignatureAPIProfile();

            // Set up your API credentials, PayPal end point, API operation and version.
            profile.setAPIUsername("web_1316757704_biz_api1.gmail.com");
            profile.setAPIPassword("1316757754");
            profile.setSignature("AFcWxV21C7fd0v3bYYYRCpSSRl31AobkBjpaOfK5wRRDT34RrVAP6RfZ");
            profile.setEnvironment("sandbox");
            profile.setSubject("");
            caller.setAPIProfile(profile);

            encoder.add("VERSION", "60.0");
            encoder.add("METHOD", "DoDirectPayment");

            // Add request-specific fields to the request string.
            encoder.add("PAYMENTACTION", paymentAction);
            encoder.add("AMT", amount);
            encoder.add("CREDITCARDTYPE", cardType);
            encoder.add("ACCT", acct);
            encoder.add("EXPDATE", expdate);
            encoder.add("CVV2", cvv2);
            encoder.add("PAYER", email);
            encoder.add("FIRSTNAME", firstName);
            encoder.add("LASTNAME", lastName);

            // Execute the API operation and obtain the response.
            String NVPRequest = encoder.encode();
            String NVPResponse = (String) caller.call(NVPRequest);
            decoder.decode(NVPResponse);

        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return decoder;
    }

    public void initOfferedGrouponList(PhaseEvent event) {
        currentlyOfferedGrouponList = grouponSessionBean.getAllCurrentlyOfferedGroupons();
    }

    public String selectOfferedGroupon() {
        //FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("selectedGroupon", selectedGroupon);
        reloadOrderPage = true;
        return "VisitorViewGroupon?faces-redirect=true";
    }

    public void initVisitorMakeOrder(PhaseEvent event) throws IOException {
        if (tourist == null) {
            setShowLoginPanel(true);
        } else {
            setShowLoginPanel(false);
        }
        if (reloadOrderPage == true || totalAmount == 0) {
            totalAmount = selectedGroupon.getGroupon().getOfferedPrice();
            purchase = new PurchasedGrouponEntity();
        }
    }

    public void calculateTotalAmount() {
        totalAmount = this.roundTwoDecimals(purchase.getQuantity() * selectedGroupon.getGroupon().getOfferedPrice());
    }

    /**
     * @return the grouponSessionBean
     */
    public GrouponSessionBean getGrouponSessionBean() {
        return grouponSessionBean;
    }

    /**
     * @return the purchase
     */
    public PurchasedGrouponEntity getPurchase() {
        return purchase;
    }

    /**
     * @param purchase the purchase to set
     */
    public void setPurchase(PurchasedGrouponEntity purchase) {
        this.purchase = purchase;
    }

    /**
     * @return the currentlyOfferedGrouponList
     */
    public List<GrouponHelper> getCurrentlyOfferedGrouponList() {
        return currentlyOfferedGrouponList;
    }

    /**
     * @return the selectedGroupon
     */
    public GrouponHelper getSelectedGroupon() {
        return selectedGroupon;
    }

    /**
     * @param selectedGroupon the selectedGroupon to set
     */
    public void setSelectedGroupon(GrouponHelper selectedGroupon) {
        this.selectedGroupon = selectedGroupon;
    }

    /**
     * @return the percentDiscount
     */
    public Integer getPercentDiscount() {
        percentDiscount = (int) (100 * (selectedGroupon.getGroupon().getOriginalPrice() - selectedGroupon.getGroupon().getOfferedPrice()) / selectedGroupon.getGroupon().getOriginalPrice());
        return percentDiscount;
    }

    /**
     * @return the savingAmount
     */
    public Double getSavingAmount() {
        savingAmount = selectedGroupon.getGroupon().getOriginalPrice() - selectedGroupon.getGroupon().getOfferedPrice();
        return savingAmount;
    }

    /**
     * @return the totalAmount
     */
    public Double getTotalAmount() {
        return totalAmount;
    }

    /**
     * @return the tourist
     */
    public TouristAccountEntity getTourist() {
        return tourist;
    }

    /**
     * @param tourist the tourist to set
     */
    public void setTourist(TouristAccountEntity tourist) {
        this.tourist = tourist;
    }

    /**
     * @return the username
     */
    public String getUsername() {
        return username;
    }

    /**
     * @param username the username to set
     */
    public void setUsername(String username) {
        this.username = username;
    }

    /**
     * @return the password
     */
    public String getPassword() {
        return password;
    }

    /**
     * @param password the password to set
     */
    public void setPassword(String password) {
        this.password = password;
    }

    /**
     * @return the expiryYearList
     */
    public List<String> getExpiryYearList() {
        return expiryYearList;
    }

    /**
     * @param expiryYearList the expiryYearList to set
     */
    public void setExpiryYearList(List<String> expiryYearList) {
        this.expiryYearList = expiryYearList;
    }

    public String getCreditCardNumberGroup1() {
        return creditCardNumberGroup1;
    }

    public void setCreditCardNumberGroup1(String creditCardNumberGroup1) {
        this.creditCardNumberGroup1 = creditCardNumberGroup1;
    }

    public String getCreditCardNumberGroup2() {
        return creditCardNumberGroup2;
    }

    public void setCreditCardNumberGroup2(String creditCardNumberGroup2) {
        this.creditCardNumberGroup2 = creditCardNumberGroup2;
    }

    public String getCreditCardNumberGroup3() {
        return creditCardNumberGroup3;
    }

    public void setCreditCardNumberGroup3(String creditCardNumberGroup3) {
        this.creditCardNumberGroup3 = creditCardNumberGroup3;
    }

    public String getCreditCardNumberGroup4() {
        return creditCardNumberGroup4;
    }

    public void setCreditCardNumberGroup4(String creditCardNumberGroup4) {
        this.creditCardNumberGroup4 = creditCardNumberGroup4;
    }

    public String getNameOnCard() {
        return nameOnCard;
    }

    public void setNameOnCard(String nameOnCard) {
        this.nameOnCard = nameOnCard;
    }

    public String getCCV2() {
        return CCV2;
    }

    public void setCCV2(String CCV2) {
        this.CCV2 = CCV2;
    }

    public String getExpiryMonth() {
        return expiryMonth;
    }

    public void setExpiryMonth(String expiryMonth) {
        this.expiryMonth = expiryMonth;
    }

    public String getExpiryYear() {
        return expiryYear;
    }

    public void setExpiryYear(String expiryYear) {
        this.expiryYear = expiryYear;
    }

    public String getCreditCardType() {
        return creditCardType;
    }

    public void setCreditCardType(String creditCardType) {
        this.creditCardType = creditCardType;
    }

    public String getHostIp() throws UnknownHostException {
        InetAddress inetAddress = InetAddress.getLocalHost();
        hostIp = inetAddress.getHostAddress();
        return hostIp;
    }

    public void setHostIp(String hostIp) {
        this.hostIp = hostIp;
    }

    public double roundTwoDecimals(double d) {
        DecimalFormat twoDForm = new DecimalFormat("#.##");
        return Double.valueOf(twoDForm.format(d));
    }

    public boolean getShowLoginPanel() {
        return showLoginPanel;
    }

    public void setShowLoginPanel(boolean showLoginPanel) {
        this.showLoginPanel = showLoginPanel;
    }

    public String getTransactionId() {
        return transactionId;
    }

    public String getCorrelationId() {
        return correlationId;
    }

    public String getPaymentDate() {
        return paymentDate;
    }
}
